package com.gemantic.task.dto;

import lombok.Getter;
import lombok.Setter;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Queue;

import org.springframework.util.Assert;

import com.gemantic.task.model.BaseTask;
import com.gemantic.task.util.TaskUtil;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

public class TaskContext<T extends BaseTask> extends BaseTask {

    private final HashMap<Class<?>, HashMap<Object, Object>> valueCache;
    private final T currentTask;
    private final Queue<BaseTask> nextTaskList = Lists.newLinkedList();
    private final List<BaseTask> backendTaskList = Lists.newLinkedList();
    @Getter
    @Setter
    private Object reqObjectData;


    public TaskContext(T task) {
        Assert.notNull(task, "taskhandler 不允许为null");
        currentTask = task;
        valueCache = Maps.newLinkedHashMap();
    }

    /**
     * @param key   缓存对象的键值
     * @param value 待缓存对象
     * @return TaskContext this
     */
    public TaskContext<T> cacheValue(Object key, Object value) {
        Assert.notNull(key, "key不允许为null.");
        Assert.notNull(value, "value不允许为null.");
        return cacheValue(key, value, value.getClass());
    }

    /**
     * @param key   缓存对象的键值
     * @param value 待缓存对象
     * @param clazz 缓存对象类型，必须与getCache 传入的值一致，才能获取到
     * @return TaskContext
     */
    public TaskContext<T> cacheValue(Object key, Object value, Class<?> clazz) {
        valueCache.computeIfAbsent(clazz,item->Maps.newLinkedHashMap());
        valueCache.get(clazz).put(key, value);
        return this;
    }

    /**
     * @param key   缓存对象的键值
     * @param clazz 缓存对象类型，必须与getCache 传入的值一致，才能获取到
     * @param <R>   待返回对象类型
     * @return R 缓存对象
     */
    public <R> R getCache(Object key, Class<R> clazz) {
        HashMap<Object, Object> clazzHash = valueCache.getOrDefault(clazz, null);
        if (clazzHash != null) {
            Object value = clazzHash.getOrDefault(key, null);
            if (value != null
                    && clazz.isInstance(value)) {
                return (R) value;
            }
        }
        return null;
    }

    /**
     * 添加下一个任务（在同一个线程中执行，最后一个任务的执行结果会作为当前线程的任务链的最终结果）
     *
     * @param task 下一个任务
     */
    public void addNextTask(BaseTask task) {
        nextTaskList.add(task);
    }

    /**
     * 添加异步执行任务（使用线程池马上任务，主线程不关心返回结果)
     *
     * @param task 待执行任务
     */
    public void addBackendTask(BaseTask task) {
        backendTaskList.add(task);
    }

    /**
     * 获取并删除下一个任务
     *
     * @return Task
     */
    public BaseTask pollNextTask() {
        return nextTaskList.poll();
    }

    /**
     * 获取并清空异步任务
     *
     * @return List
     */
    public List<BaseTask> pollAllBackendTask() {
        ImmutableList<BaseTask> result = ImmutableList.copyOf(backendTaskList);
        backendTaskList.clear();
        return result;
    }

    @Override
    public String getRequestData() {
        return currentTask.getRequestData();
    }

    @Override
    public String getResponseData() {
        return currentTask.getResponseData();
    }

    @Override
    public void setResponseData(String responseData) {
        currentTask.setResponseData(responseData);
    }

    public Long getId() {
        return currentTask.getPrimaryKey();
    }

    @Override
    public Long getPrimaryKey() {
        return currentTask.getPrimaryKey();
    }

    @Override
    public Integer getRetryTimes() {
        return currentTask.getRetryTimes();
    }

    @Override
    public String getType() {
        return currentTask.getType();
    }

    @Override
    public String getOrderNo() {
        return currentTask.getOrderNo();
    }

    @Override
    public void setRemark(String remark) {
        currentTask.setRemark(remark);
    }

    @Override
    public String getStatus() {
        return currentTask.getStatus();
    }

    @Override
    public Date getNextRunTime() {
        return currentTask.getNextRunTime();
    }

    @Override
    public Date getCreateTime() {
        return currentTask.getCreateTime();
    }

    /**
     * 当前task对象
     *
     * @return BaseTask
     */
    public T getCurrentTask() {
        return currentTask;
    }

    @Override
    public Integer getMaxRetryTimes() {
        Integer maxRetryTimes = currentTask.getMaxRetryTimes();
        if (maxRetryTimes == null || maxRetryTimes <= 0) {
            maxRetryTimes = TaskUtil.getMaxRetryTimes();
        }
        return maxRetryTimes;
    }
}